#include "../co_async/steps/co_async/debug.hpp"
#include <chrono>
#include <coroutine>
#include <deque>
#include <exception>
#include <functional>
#include <queue>
#include <span>
#include <thread>
#include <utility>
#include <variant>

/**
 * 【【C++20】从0开始自制协程库，有手就行（上）】https://www.bilibili.com/video/BV1Yz421Z7rZ
 1:26:23
 *
 */

using namespace std::chrono_literals;

// 非void类型的，Type=T
template <class T = void>
struct NonVoidHelper {
    using Type = T;
};

// void类型的，Type=NonVoidHelper
template <>
struct NonVoidHelper<void> {
    using Type = NonVoidHelper;
    // explicit 防止隐式类型转换
    explicit NonVoidHelper() = default;
};

template <class T>
struct Uninitialized {
    union {
        T mvalue;
    };

    Uninitialized() noexcept {}

    Uninitialized(Uninitialized &&) = delete;

    ~Uninitialized() noexcept {}

    T moveValue() {
        T ret(std::move(mvalue));
        mvalue.~T();
        return ret;
    }

    template <class... Ts>
    void putValue(Ts &&...args) {
        new (std::addressof(mvalue)) T(std::forward<Ts>(args)...);
    }
};

template <>
struct Uninitialized<void> {
    auto moveValue() {
        return NonVoidHelper<>{};
    }

    void putValue(NonVoidHelper<>) {}
};

template <class T>
struct Uninitialized<T const> : Uninitialized<T> {};

template <class T>
struct Uninitialized<T &> : Uninitialized<std::reference_wrapper<T>> {};

template <class T>
struct Uninitialized<T &&> : Uninitialized<T> {};

template <class A>
concept Awaiter = requires(A a, std::coroutine_handle<> h) {
    { a.await_ready() };
    { a.await_suspend(h) };
    { a.await_resume() };
};

template <class A>
concept Awaitable = Awaiter<A> || requires(A a) {
    { a.operator co_await() } -> Awaiter;
};

template <class A>
struct AwaitableTraits;

template <Awaiter A>
struct AwaitableTraits<A> {
    using RetType = decltype(std::declval<A>().await_resume());
    using NonVoidRetType = NonVoidHelper<RetType>::Type;
};

// 当A不是Awaiter，但是是Awaitable时，A.operator co_await()返回的Awaiter
// 也就是说，当A是Awaitable时，编译器自动将其转换为Awaiter。
template <class A>
    requires(!Awaiter<A> && Awaitable<A>)
struct AwaitableTraits<A>
    : AwaitableTraits<decltype(std::declval<A>().operator co_await())> {};

struct RepeatAwaiter {
    bool await_ready() const noexcept {
        return false;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const noexcept {
        if (coroutine.done()) {
            return std::noop_coroutine();
        } else {
            return coroutine;
        }
    }

    void await_resume() const noexcept {}
};

struct PreviousAwaiter {
    std::coroutine_handle<> mPrevious = nullptr;

    constexpr bool await_ready() const noexcept {
        return false;
    }

    constexpr std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const noexcept {
        if (mPrevious) {
            return mPrevious;
        } else {
            return std::noop_coroutine();
        }
    }

    constexpr void await_resume() const noexcept {}
};

template <class T>
struct Promise {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";

        mException = std::current_exception();
    }

    void return_value(T &&ret) {
        mResult.putValue(std::move(ret));
    }

    void return_value(T const &ret) {
        mResult.putValue(ret);
    }

    // 返回引用，这样外面就可以将result移动出去。（而不是拷贝？）
    T result() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
        return mResult.moveValue();
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious{};
    std::exception_ptr mException{};
    Uninitialized<T> mResult;

    Promise &operator=(Promise &&) = delete;
};

template <>
struct Promise<void> {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        mException = std::current_exception();
    }

    void return_void() {}

    void result() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;

    // 返回值
    std::exception_ptr mException{};

    Promise() = default;
    Promise(Promise &&) = delete;
    ~Promise() = default;
};

template <class T = void>
struct Task {
    using promise_type = Promise<T>;

    Task(std::coroutine_handle<promise_type> coroutine)
        : mCoroutine(coroutine) {}

    // 为什么说根据“三无法则”就要写这一行？移动构造？
    Task(Task &&) = delete;

    ~Task() {
        mCoroutine.destroy();
    }

    struct Awaiter {
        bool await_ready() const noexcept {
            return false;
        }

        std::coroutine_handle<>
        await_suspend(std::coroutine_handle<> coroutine) const noexcept {
            mCoroutine.promise().mPrevious = coroutine;

            return mCoroutine;
        }

        // 返回协程co_return的返回值值。
        T await_resume() const noexcept {
            return mCoroutine.promise().result();
        }

        std::coroutine_handle<promise_type> mCoroutine;
    };

    auto operator co_await() const noexcept {
        return Awaiter(mCoroutine);
    }

    operator std::coroutine_handle<>() const noexcept {
        return mCoroutine;
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

// 调度器
struct Loop {
    std::deque<std::coroutine_handle<>> mReadyQueue;

    struct TimerEntry {
        std::chrono::system_clock::time_point expireTime;
        std::coroutine_handle<> coroutine;

        // 重载<运算符，与大顶堆配合使用
        bool operator<(TimerEntry const &that) const noexcept {
            return expireTime > that.expireTime;
        }
    };

    // 大顶堆，top返回最大的值
    std::priority_queue<TimerEntry> mTimerHeap;

    void addTask(std::coroutine_handle<> t) {
        mReadyQueue.push_front(t);
    }

    void addTimer(std::chrono::system_clock::time_point expireTime,
                  std::coroutine_handle<> t) {
        mTimerHeap.push({expireTime, t});
    }

    void runAll() {
        while (!mTimerHeap.empty() || !mReadyQueue.empty()) {
            while (!mReadyQueue.empty()) {
                auto readyTask = mReadyQueue.front();
                debug(), "pop";
                mReadyQueue.pop_front();
                readyTask.resume();
            }
            if (!mTimerHeap.empty()) {
                auto nowTime = std::chrono::system_clock::now();
                auto timer = std::move(mTimerHeap.top());
                if (timer.expireTime < nowTime) {
                    mTimerHeap.pop();
                    timer.coroutine.resume();
                } else {
                    std::this_thread::sleep_until(timer.expireTime);
                }
            }
        }
    }

    // 为了防止一不小心拷贝了。
    // 所以把移动赋值删了，这样其他的构造函数也都默认删了（但是保留默认构造）。
    Loop &operator=(Loop &&) = delete;
};

Loop &getLoop() {
    static Loop loop;
    return loop;
}

struct SleepAwaiter {
    bool await_ready() const {
        return false;
    }

    void await_suspend(std::coroutine_handle<> coroutine) const {
        getLoop().addTimer(mExpireTime, coroutine);
    }

    void await_resume() const {}

    std::chrono::system_clock::time_point mExpireTime;
};

Task<void> sleep_until(std::chrono::system_clock::time_point expireTime) {
    co_await SleepAwaiter(expireTime);
}

Task<void> sleep_for(std::chrono::system_clock::duration duration) {
    co_await SleepAwaiter(std::chrono::system_clock::now() + duration);
}

struct CurrentCoroutineAwaiter {
    bool await_ready() const noexcept {
        return false;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) noexcept {
        mCurrent = coroutine;
        return mCurrent;
    }

    auto await_resume() const noexcept {
        return mCurrent;
    }

    std::coroutine_handle<> mCurrent;
};

struct ReturnPreviousPromise {
    auto initial_suspend() noexcept {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        mException = std::current_exception();
    }

    void return_value(std::coroutine_handle<> previous) noexcept {
        mPrevious = previous;
    }

    void rethrow_if_any() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    std::coroutine_handle<ReturnPreviousPromise> get_return_object() {
        return std::coroutine_handle<ReturnPreviousPromise>::from_promise(
            *this);
    }

    std::coroutine_handle<> mPrevious{};
    std::exception_ptr mException{};

    ReturnPreviousPromise &operator=(ReturnPreviousPromise &&) = delete;
};

struct ReturnPreviousTask {
    using promise_type = ReturnPreviousPromise;

    ReturnPreviousTask(std::coroutine_handle<promise_type> coroutine) noexcept
        : mCoroutine(coroutine) {}

    ReturnPreviousTask(ReturnPreviousTask &&) = delete;

    ~ReturnPreviousTask() {
        mCoroutine.destroy();
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

struct WhenAllCounterBlock {
    // mCount减为0的时候，唤醒
    std::size_t mCount{};
    std::coroutine_handle<> mPrevious{};
};

struct WhenAllAwaiter {
    bool await_ready() const noexcept {
        return false;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const {
        if (mTasks.empty()) {
            return coroutine;
        }
        mControl.mPrevious = coroutine;
        for (auto const &t: mTasks.subspan(1)) {
            getLoop().addTask(t.mCoroutine);
        }
        return mTasks.front().mCoroutine;
    }

    void await_resume() const noexcept {
        for (auto &t: mTasks) {
            t.mCoroutine.promise().rethrow_if_any();
        }
    }

    WhenAllCounterBlock &mControl;
    std::span<ReturnPreviousTask const> mTasks;
};

template <class T>
ReturnPreviousTask whenAllHelper(Task<T> const &t, WhenAllCounterBlock &counter,
                                 Uninitialized<T> &result) {
    result.putValue(co_await t);
    counter.mCount--;
    std::coroutine_handle<> previous = nullptr;
    if (counter.mCount == 0) {
        previous = counter.mPrevious;
    }
    co_return previous;
}

template <std::size_t... Is, class... Ts>
Task<std::tuple<typename AwaitableTraits<Ts>::NonVoidRetType...>>
whenAllImpl(std::index_sequence<Is...>, Ts &&...ts) {
    WhenAllCounterBlock counter{sizeof...(Ts)};
    std::tuple<Uninitialized<typename AwaitableTraits<Ts>::RetType>...> result;
    ReturnPreviousTask taskArray[]{
        whenAllHelper(ts, counter, std::get<Is>(result))...};
    co_await WhenAllAwaiter(counter, taskArray);
    co_return std::tuple<typename AwaitableTraits<Ts>::NonVoidRetType...>(
        std::get<Is>(result).moveValue()...);
}

// 这里可以支持任意数量参数，但是参数数量至少要为1
template <Awaitable... Ts>
    requires(sizeof...(Ts) != 0)
auto when_all(Ts &&...ts) {
    return whenAllImpl(std::make_index_sequence<sizeof...(Ts)>{},
                       std::forward<Ts>(ts)...);
}

struct WhenAnyCtlBlock {
    static constexpr std::size_t kNullIndex = std::size_t(-1);

    std::size_t mIndex{kNullIndex};
    std::coroutine_handle<> mPrevious{};
    std::exception_ptr mException{};
};

struct WhenAnyAwaiter {
    bool await_ready() const noexcept {
        return false;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const {
        if (mTasks.empty()) {
            return coroutine;
        }
        mControl.mPrevious = coroutine;
        for (auto const &t: mTasks.subspan(0, mTasks.size() - 1)) {
            t.mCoroutine.resume();
        }
        return mTasks.back().mCoroutine;
    }

    void await_resume() const noexcept {
        for (auto &t: mTasks) {
            t.mCoroutine.promise().rethrow_if_any();
        }
    }

    WhenAnyCtlBlock &mControl;
    std::span<ReturnPreviousTask const> mTasks;
};

template <class T>
ReturnPreviousTask whenAnyHelper(Task<T> const &t, WhenAnyCtlBlock &mControl,
                                 Uninitialized<T> &result) {
    try {
        result.putValue(co_await t);
    } catch (...) {
        mControl.mException = std::current_exception();
        debug(), "whenAnyHelper catch exception";
        co_return mControl.mPrevious;
    }
    --mControl.mIndex;
    co_return mControl.mPrevious;
}

template <std::size_t... Is, class... Ts>
Task<std::variant<typename AwaitableTraits<Ts>::NonVoidRetType...>>
whenAnyImpl(std::index_sequence<Is...>, Ts &&...ts) {
    WhenAnyCtlBlock control{};
    // 这里RetType代表的是Task中await_resume的返回类型。
    std::tuple<Uninitialized<typename AwaitableTraits<Ts>::RetType>...> result;
    ReturnPreviousTask taskArray[]{
        whenAnyHelper(ts, control, std::get<Is>(result))...};
    co_await WhenAnyAwaiter(control, taskArray);
    Uninitialized<std::variant<typename AwaitableTraits<Ts>::NonVoidRetType...>> varResult;
    ((control.mIndex == Is && (varResult.putValue(
        std::in_place_index<Is>, std::get<Is>(result).moveValue()), 0)), ...);
    co_return varResult.moveValue();
}

template <Awaitable... Ts>
    requires(sizeof...(Ts) != 0)
auto when_any(Ts &&...ts) {
    return whenAnyImpl(std::make_index_sequence<sizeof...(Ts)>{},
                       std::forward<Ts>(ts)...);
}

Task<int> hello1() {
    debug(), "hello1 begin to sleep 1s";
    co_await sleep_for(1s);
    debug(), "hello1 had sleep for 1s done";
    co_return 1;
}

Task<int> hello2() {
    debug(), "hello2 begin to sleep 2s";
    co_await sleep_for(2s);
    debug(), "hello2 had sleep 2s done";
    co_return 2;
}

// Task<int> hello() {
//     debug(), "hello开始等1和2";
//     auto [i, j, k] = co_await when_all(hello1(), hello2(), hello2());
//     debug(), "1 和2都睡醒了";
//     co_return i + j + k;
// }

Task<int> hello() {
    debug(), "hello开始等1和2";
    auto v =
        co_await when_any(hello1(), hello2(), hello2());
    debug(), std::get<0>(v), " ", std::get<1>(v), " ", std::get<2>(v);
    debug(), "hello看到" , (int)v.index() + 1, "睡醒了";
    co_return std::get<0>(v);
}

int main() {
    auto t = hello();
    getLoop().addTask(t);
    getLoop().runAll();
    debug(), "主函数中得到hello结果：", t.mCoroutine.promise().result();
    return 0;
}
